package com.iflytek.jzcpx.procuracy.ocr.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iflytek.jzcpx.procuracy.ocr.common.constant.Constants;
import com.iflytek.jzcpx.procuracy.ocr.common.enums.OcrFileStatusEnum;
import com.iflytek.jzcpx.procuracy.ocr.common.enums.TaskFileTypeEnum;
import com.iflytek.jzcpx.procuracy.ocr.common.helper.SwxRequestHelper;
import com.iflytek.jzcpx.procuracy.ocr.dao.OcrFileDao;
import com.iflytek.jzcpx.procuracy.ocr.entity.OcrFile;
import com.iflytek.jzcpx.procuracy.ocr.service.OcrFileService;
import com.iflytek.jzcpx.procuracy.tools.common.PropUtils;
import com.iflytek.sxs.dfs.client.FdfsClient;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019-08-12 19:26
 */
@Service
public class OcrFileServiceImpl extends ServiceImpl<OcrFileDao, OcrFile> implements OcrFileService {
    private static final Logger logger = LoggerFactory.getLogger(OcrFileServiceImpl.class);

    @Autowired
    private SwxRequestHelper swxRequestHelper;
    @Autowired
    private FdfsClient fdfsClient;


    @Override
    public boolean abnormalEnd(Long id, String errorInfo) {
        OcrFile params = new OcrFile();
        params.setId(id);
        params.setUpdateTime(new Date());
        params.setFailInfo(errorInfo);
        params.setStatus(OcrFileStatusEnum.END.toString());
        logger.info("ocr 识别子任务异常结束, id[ {} ], errorInfo[ {} ]", id, errorInfo);
        return updateById(params);
    }

    @Override
    public boolean updateStatus(Long fileId, OcrFileStatusEnum targetStatusEnum) {
        OcrFile params = new OcrFile();
        params.setId(fileId);
        params.setUpdateTime(new Date());
        params.setStatus(targetStatusEnum.toString());
        logger.info("更新 ocr 识别文件子任务状态, fileId[ {} ], targetStatusEnum[ {} ]", fileId, targetStatusEnum);
        return updateById(params);
    }

    @Override
    public boolean updateEngineResultPath(Long fileId, String storePath) {
        OcrFile params = new OcrFile();
        params.setId(fileId);
        params.setState(Constants.STATE_NOT_DELETED);
        params.setUpdateTime(new Date());
        params.setEngineResultPath(storePath);
        params.setStatus(OcrFileStatusEnum.ENGINE_RESULT_STORE.toString());
        logger.info("更新 ocr 引擎识别结果保存路径, fileId[ {} ], storePath[ {} ]", fileId, storePath);
        return updateById(params);
    }

    @Override
    public Long createSingle(String wjbh) {
        Date now = new Date();
        OcrFile ocrFile = new OcrFile();
        ocrFile.setCreateTime(now);
        ocrFile.setUpdateTime(now);
        ocrFile.setStatus(OcrFileStatusEnum.INIT.toString());
        ocrFile.setType(TaskFileTypeEnum.SINGLE.toString());
        ocrFile.setWjxh(wjbh);
        ocrFile.setOcrTaskId(0L);
        ocrFile.setState(Constants.STATE_NOT_DELETED);

        boolean saveSucces = save(ocrFile);
        logger.info("新增单文件识别记录. id: {}, wjbh: {}", ocrFile.getId(), wjbh);
        return saveSucces ? ocrFile.getId() : null;

    }

    @Override
    public Map<Long, List<Long>> findUndoneFileIdMap(List<Long> taskIdList) {
        if (CollectionUtils.isEmpty(taskIdList)) {
            return null;
        }

        //存在海量taskIdList导致查询任务失败 默认达梦2048
        List<OcrFile> dataList = new ArrayList<>();
        int size = taskIdList.size();
        int step = PropUtils.getInt("undone_file_step", 50);
        int lastIndex = 0;
        try {
            do {
                int endIndex = Math.min(lastIndex + step, size);
                List<Long> subIds = taskIdList.subList(lastIndex, endIndex);

                List<OcrFile> consumerAlerts = findUndoneFiles(subIds);
                if (CollectionUtils.isNotEmpty(consumerAlerts)) {
                    dataList.addAll(consumerAlerts);
                }

                lastIndex = endIndex;
            } while (lastIndex <= size - 1);
        }
        catch (Exception e) {
            logger.warn("SQL查询异常", e);
        }

        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }

        return dataList.stream().collect(
                Collectors.groupingBy(OcrFile::getOcrTaskId, Collectors.mapping(OcrFile::getId, Collectors.toList())));
    }

    private List<OcrFile> findUndoneFiles(List<Long> taskIds) {
        if (CollectionUtils.isEmpty(taskIds)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<OcrFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(OcrFile::getId, OcrFile::getOcrTaskId);
        wrapper.ne(OcrFile::getStatus, OcrFileStatusEnum.END.name());
        wrapper.in(OcrFile::getOcrTaskId, taskIds);
        return list(wrapper);
    }

    @Override
    public List<OcrFile> findByOcrTaskId(Long ocrTaskId) {
        if (ocrTaskId == null) {
            return null;
        }

        QueryWrapper<OcrFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OcrFile::getOcrTaskId, ocrTaskId);
        return list(queryWrapper);
    }

    @Override
    public List<OcrFile> findBybmsah(String bmsah) {

        QueryWrapper<OcrFile> queryWrapper = new QueryWrapper<>();
        //queryWrapper.lambda().eq(OcrFile::getBmsah, bmsah);
        queryWrapper.lambda().like(OcrFile::getBmsah, bmsah);

        List<OcrFile> result = list(queryWrapper);
        return result;
    }

    @Override
    public List<OcrFile> findByWjxh(List<String> wjxhList) {

        QueryWrapper<OcrFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(OcrFile::getWjxh, wjxhList);

        List<OcrFile> result = list(queryWrapper);
        return result;
    }

    @Override
    public List<OcrFile> getOcrByBSBH(String bsbh) {
        if (bsbh == null) {
            return null;
        }

        QueryWrapper<OcrFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OcrFile::getBsbh, bsbh);
        return list(queryWrapper);
    }

    /**
     * 补充一个下载图片的方法
     *
     * @param bsbh
     * @param taskid
     * @param wjxh
     *
     * @return
     */
    @Override
    public byte[] getDZJZJPG(String bsbh, String taskid, String wjxh) {
        byte[] fileDatas = null;
        try {
            fileDatas = swxRequestHelper.getDZJZJPG(bsbh, taskid, wjxh).getData().getData();
        }
        catch (Exception ex) {

        }
        return fileDatas;
    }

    @Override
    public OcrFile findOcrFileByWjxh(String wjxh) {
        QueryWrapper<OcrFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OcrFile::getWjxh, wjxh);
        List<OcrFile> list = list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }

        return list.stream().filter(ocrFile -> ocrFile.getCreateTime() != null).max(
                Comparator.comparing(OcrFile::getCreateTime)).orElse(null);
    }

    @Override
    public List<OcrFile> listByBsbhWjxh(String bsbh, List<String> wjxh) {
        if (CollectionUtils.isEmpty(wjxh) && StringUtils.isBlank(bsbh)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<OcrFile> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(bsbh)) {
            queryWrapper.eq(OcrFile::getBsbh, bsbh);
        }
        if (CollectionUtils.isNotEmpty(wjxh)) {
            queryWrapper.in(OcrFile::getWjxh, wjxh);
        }
        return list(queryWrapper);
    }

    @Override
    public int cleanData(Date startDatetime, Date endDatetime, boolean cleanDB, boolean cleanFdfs) {
        if (!cleanDB && !cleanFdfs) {
            logger.warn("即不清理DB, 又不清理fastDFS, 你清理个毛啊");
            return 0;
        }

        logger.info("清理ocrFile数据, 起止时间: {} - {}", startDatetime, endDatetime);
        Assert.isTrue(startDatetime != null || endDatetime != null, "开始和结束时间不能同时为空");

        int cleanCount = 0;

        List<OcrFile> ocrFiles = null;
        int pageSize = 100;
        int pagetNum = 1;
        do {
            Page<OcrFile> page = new Page<>(pagetNum, pageSize);
            LambdaQueryWrapper<OcrFile> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(OcrFile::getId, OcrFile::getOcrResultPath, OcrFile::getEngineResultPath);
            if (startDatetime != null) {
                wrapper.gt(OcrFile::getCreateTime, startDatetime);
            }
            if (endDatetime != null) {
                wrapper.lt(OcrFile::getCreateTime, endDatetime);
            }
            IPage<OcrFile> ocrFilePage = this.baseMapper.selectPage(page, wrapper);
            if (ocrFilePage == null || CollectionUtils.isEmpty(ocrFilePage.getRecords())) {
                logger.info("没有待清理的ocrFile数据了");
                return cleanCount;
            }

            ocrFiles = ocrFilePage.getRecords();
            logger.debug("查询到待清理的ocrFile数据, size: {}, page: {}", ocrFiles.size(), page);

            for (OcrFile ocrFile : ocrFiles) {
                if (deleteDataAndFile(ocrFile, cleanDB, cleanFdfs)) {
                    cleanCount++;
                }
            }

            if (!cleanDB) {
                pagetNum++;
            }
        } while (CollectionUtils.size(ocrFiles) >= pageSize);

        return cleanCount;
    }

    private boolean deleteDataAndFile(OcrFile ocrFile, boolean cleanDB, boolean cleanFdfs) {
        logger.info("删除ocrFile数据, ocrFile: {}", ocrFile);
        if (cleanDB) {
            logger.info("删除ocrFile数据库数据, id: {}", ocrFile.getId());
            removeById(ocrFile);
        }
        if (cleanFdfs) {
            String ocrResultPath = ocrFile.getOcrResultPath();
            String engineResultPath = ocrFile.getEngineResultPath();
            if (StringUtils.isNotBlank(ocrResultPath)) {
                logger.info("删除fastDFS文件, ocrFileId: {}, ocrResultPath: {}", ocrFile.getId(), ocrResultPath);
                try {
                    fdfsClient.deleteFile(ocrResultPath);
                }
                catch (Exception e) {
                    logger.warn("删除fastDFS文件异常, ocrFileId: {}, ocrResultPath: {}, errorInfo: {}", ocrFile.getId(),
                                ocrResultPath, e.getMessage());
                }
            }

            if (StringUtils.isNotBlank(engineResultPath)) {
                logger.info("删除fastDFS文件, ocrFileId: {}, engineResultPath: {}", ocrFile.getId(), engineResultPath);
                try {
                    fdfsClient.deleteFile(engineResultPath);
                }
                catch (Exception e) {
                    logger.warn("删除fastDFS文件异常, ocrFileId: {}, engineResultPath: {}, errorInfo: {}", ocrFile.getId(),
                                engineResultPath, e.getMessage());
                }
            }

        }
        return true;
    }

}
